/**
 * File name: ARFFFileWriter.java Author: Willard Wang Create date: Jul 21, 2013
 */
package edu.sjtu.se.prophet.io;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import edu.sjtu.se.prophet.graph.Branch;
import edu.sjtu.se.prophet.graph.Graph;
import edu.sjtu.se.prophet.graph.Node;
import edu.sjtu.se.prophet.utils.GraphUtil;

/**
 * @author deathspeeder
 * 
 */
public class ARFFFileWriter {
    private static String[] VALID_METRICS = new String[] { "CountInput",
            "CountLineCode", "CountOutput", "CountPath", "Cyclomatic",
            "Essential", "MaxNesting", "RatioCommentToCode" };

    private BufferedWriter br;
    private float depth;
    private int count;

    public ARFFFileWriter(float depth, int count) {
        this.depth = depth;
        this.count = count;
    }

    public void writeBranchARFF(List<Graph> graphs) throws IOException {
        br = new BufferedWriter(new FileWriter(new File("data-branch.arff")));
        writeHeaders("branches");
        writeBranchData(graphs);
        br.close();
    }

    public void writeFunctionARFF(List<Graph> graphs) throws IOException {
        br = new BufferedWriter(new FileWriter(new File("data-function.arff")));
        writeHeaders("function");
        writeFunctionData(graphs);
        br.close();
    }

    /**
     * @param graphs
     */
    private void writeFunctionData(List<Graph> graphs) throws IOException {
        br.append("@DATA\n");
        for (Graph graph : graphs) {
            for (Node node : graph.getNodes()) {
                StringBuffer buffer = new StringBuffer();
                //boolean nullFlag = false;
                for (int i = 0; i < VALID_METRICS.length; i++) {
                    Object obj = node.getMetrics().get(VALID_METRICS[i]);
//                    if (obj == null)
//                        nullFlag = true;
                    buffer.append(obj);
                    buffer.append(",");
                }
                buffer.append(getLevel((Integer) node.getMetrics().get(
                        IOCommon.BUG_COUNT)));
//                if (!nullFlag)
                    br.append(buffer.toString() + "\n");
            }
        }
    }

    /**
     * @param graphs
     * @throws IOException
     */
    private void writeBranchData(List<Graph> graphs) throws IOException {
        br.append("@DATA\n");
        for (Graph graph : graphs) {
            for (Branch branch : GraphUtil.generateBranch(graph)) {
                StringBuffer buffer = new StringBuffer();
                for (int i = 0; i < VALID_METRICS.length; i++) {
                    buffer.append(branch.getAverageMetric(VALID_METRICS[i]));
                    buffer.append(",");
                }
                buffer.append(getLevel(branch
                        .getAverageMetric(IOCommon.BUG_COUNT)));
                br.append(buffer.toString() + "\n");
            }
        }
    }

    /**
     * @param averageMetric
     * @return
     */
    private String getLevel(float avgBug) {
        for (int i = 1; i <= count; i++) {
            if (avgBug < depth * i)
                return "Level" + i;
        }
        return "Level" + count;
    }

    /**
     * @throws IOException
     * 
     */
    private void writeHeaders(String name) throws IOException {
        br.append("@RELATION " + name + "\n");
        for (int i = 0; i < VALID_METRICS.length; i++) {
            br.append("@ATTRIBUTE " + VALID_METRICS[i] + " NUMERIC\n");
        }
        StringBuffer buffer = new StringBuffer();
        for (int i = 1; i <= count; i++) {
            buffer.append("Level" + i + ",");
        }
        if (buffer.length() > 0)
            buffer.deleteCharAt(buffer.length() - 1);
        br.append("@ATTRIBUTE Bugs {" + buffer.toString() + "}\n");
    }
}
